/*
    Borealis Library
    A library of commonly used hydrological modeling building blocks

    Copyright (C) 2008  Chris Marsh

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef REGEXTOKENIZER_H
#define REGEXTOKENIZER_H

#include <string>
#include <vector>
#include <exception>

#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/any.hpp>


namespace Borealis
{

	// Class: RegexTokenizer
	//	A class that allows one to tokenize a string based on a regular expression
	class RegexTokenizer
	{
		public:
			const std::string FLOAT_REGEX;
			/*
				Function: RegexTokenizer
					 Creates an empty tokenizer
				
				Parameters: 
					None

				Throws:
					Never
				
				Returns:   
					 - 
			*/
			RegexTokenizer();

			~RegexTokenizer();


			/*
				Function: RegexTokenizer
					 Creates a tokenizer with a given regex
				
				Parameters: 
					std::string regex - A valid regular expression
					bool case_senstive - default = true
				
				Throws:
					If an incorrect regex is entered, it will not throw. When you use <Tokenize> an exception will be thrown.
				
				Returns:   
					 - 
			*/
			RegexTokenizer(std::string regex, bool case_senstive = true);

			/*
				Function: SetExpression
					Sets the regular expression to use. Does not throw on an invalid regex.

				Parameters:
					exp - A valid regular expression.
					case_sensitive - Defines if a regex search should be case sensitive. Defaults to true (case sensitive).

				Throws:
					std::runtime_error on invalid regex

				Returns:
					void
			 */
			void SetExpression(std::string exp,bool case_sensitive = true);


			/*
				Function: GetExpression
					Returns the current regular expression

				Parameters:
					None.

				Throws:
					Never.

				Returns:
					std::string - String representation of the regular expression
			*/
			std::string GetExpression();


			/*
				Function: Tokenize
					Tokenizes the given item. Each match is put into the returning vector

				Parameters:
					std::string item - String to tokenize.

				Throws:
					std::runtime_error - Thrown on either:
												a) an invalid cast b/w type T and the result from the regular
													expression match ( "asdf" -> int).
												b) an invalid regular expression

				Returns:
					 A vector holding each match.
			*/
			template<typename T>
			std::vector<T> Tokenize( std::string item )
			{
				boost::match_results<std::string::const_iterator> what;
				
				std::string::const_iterator start = item.begin();
				std::string::const_iterator end = item.end();

				std::vector<T> items;



				while (boost::regex_search(start, end, what, re))
				{
					try
					{
						items.push_back(boost::lexical_cast<T>(what[0]));
					}
					catch (boost::bad_lexical_cast)
					{
						throw std::runtime_error("Bad lexical cast");
					}


					// Update the beginning of the range to the character
					// following the match
					start = what[0].second;
				}

				return items;
			}


			//TODO:
			//Copy constructor

	private:
			//regular expression
			boost::regex re;

	};
};

#endif